/* SPDX-License-Identifier: GPL-2.0 */

/* based on ubpf */

#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>

#include "common.h"
#include "./common/common_defines.h"
#include "./common/common_params.h"
#include "./common/common_user_bpf_xdp.h"
#include "./libbpf/src/bpf.h"
#include "ip_mac_conv.h"

#ifndef PATH_MAX
#define PATH_MAX	4096
#endif


static const char *__doc__ = "SRv4 User Program\n"
	" - Allows setting and listing MAPS(SID|PATH|FLOW|REDIRECT) to attach to --dev\n";

const char *pin_basedir =  "/sys/fs/bpf";
const char *sidmap_name    =  "sidmap";
const char *patmap_name    =  "pathmap";
const char *flwmap_name    =  "flowmap";
const char *rdtmap_name    =  "redirect_map";
const char *arpmap_name    =  "arpmap";

static const struct option_wrapper long_options[] = {
	{{"help",        no_argument,		NULL, 'h' },
	 "Show help", false},

	{{"dev",         required_argument,	NULL, 'D' },
	 "Operate on device <ifname>", "<ifname>", true},

	{{"list",    	required_argument,	NULL, 'l' },
	 "list entries in map <mapcode(s|sid, p|path, f|flow, A|redirect)>", "<mapcode>", false},

	{{"addpath", 	required_argument,	NULL, 'p' },
	 "add a path which is <ip1,ip2,ip3...>", "<ip1,ip2,ip3...>", false},

	{{"addsid", 	required_argument,	NULL, 's' },
	 "add a sid whose ip is <ip> SID is <SID>", "<IP> -a <SID>", false},

	{{"addflow", 	required_argument,	NULL, 'f' },
	 "add a flow who is <sip,dip,sport,dport> path is <pathnum> timeout is <TIMEOUT>", "<sip,dip,sport,dport> -n <pathnum> -t <timeout>", false},

	{{0, 0, NULL,  0 }}
};



int
map_lookup(const char *ifname, const char *map_name, struct bpf_map_info *mapinfo)
{
	struct bpf_map_info map_expect = { 0 };
	char pin_dir[PATH_MAX];
	int stats_map_fd;

	/* Use the --dev name as subdir for finding pinned maps */
	int len = snprintf(pin_dir, PATH_MAX, "%s/%s", pin_basedir, ifname);
	if (len < 0) {
		fprintf(stderr, "ERR: creating pin dirname\n");
		return EXIT_FAIL_OPTION;
	}

	map_expect.key_size    = mapinfo->key_size;
	map_expect.value_size  = mapinfo->value_size;
	map_expect.max_entries = mapinfo->max_entries;
	memset(mapinfo, 0, sizeof(struct bpf_map_info));
	stats_map_fd = open_bpf_map_file(pin_dir, map_name, mapinfo);
	if (stats_map_fd < 0) {
		return -1;
	}

	/* check map info, e.g. datarec is expected size */
	int err = check_map_fd_info(mapinfo, &map_expect);
	if (err) {
		fprintf(stderr, "ERR: map via FD not compatible\n");
		return -1;
	}
	return stats_map_fd;
}


int
find_min_available_key_sid(char* net)
{
	//------------- find sid map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct SID);
	mapinfo.max_entries = MAX_SID_NUM;
	int map_fd;
	map_fd = map_lookup(net, sidmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", sidmap_name);
		exit(-1);
	}
	//------------- find sid map end ----------

	__u32 key = -1;
	int mkey = 0;
	struct SID sid;
	int err;
	void *keyp = &key, *prev_keyp = NULL;
	while (true)
	{
        err = bpf_map_get_next_key(map_fd, prev_keyp, keyp);
        if (err) {
            if (errno == ENOENT)
                err = 0;
            break;
        }

        if ((bpf_map_lookup_elem(map_fd, keyp, &sid)) != 0) 
		{
            fprintf(stderr,
                "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
            continue;
        }
		if (!sid.valid)
		{
			mkey = *(int*)keyp;
			break;
		}
        prev_keyp = keyp;
	}

  return mkey;
}

int
find_min_available_key_path(char* net)
{
	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct PATH);
	mapinfo.max_entries = MAX_PATH_NUM;
	int map_fd;
	map_fd = map_lookup(net, patmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find path map %s\n", patmap_name);
		exit(-1);
	}
	//------------- find sid path end ----------

	__u32 key = -1;
	int mkey = 0;
	struct PATH path;
	int err;
	void *keyp = &key, *prev_keyp = NULL;
	while (true)
	{
        err = bpf_map_get_next_key(map_fd, prev_keyp, keyp);
        if (err) {
            if (errno == ENOENT)
                err = 0;
            break;
        }

        if ((bpf_map_lookup_elem(map_fd, keyp, &path)) != 0) 
		{
            fprintf(stderr,
                "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
            continue;
        }
		if (!path.valid)
		{
			mkey = *(int*)keyp;
			break;
		}
        prev_keyp = keyp;
	}

  return mkey;
}

int
find_min_available_key_flow(char* net)
{
	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct FLOW);
	mapinfo.max_entries = MAX_FLOW_NUM;
	int map_fd;
	map_fd = map_lookup(net, flwmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find flow map %s\n", flwmap_name);
		exit(-1);
	} 
	//------------- find sid path end ----------

	__u32 key = -1;
	int mkey = 0;
	struct FLOW flow;
	int err;
	void *keyp = &key, *prev_keyp = NULL;
	while (true)
	{ 
        err = bpf_map_get_next_key(map_fd, prev_keyp, keyp);
        if (err) {
            if (errno == ENOENT)
                err = 0;
            break;
        }

        if ((bpf_map_lookup_elem(map_fd, keyp, &flow)) != 0) 
		{
            fprintf(stderr,
                "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
            continue;
        }
		if (!flow.valid)
		{
			mkey = *(int*)keyp;
			break;
		}
        prev_keyp = keyp;
	}

  return mkey;
}

int
find_min_available_key_redirect(char* net)
{
	//------------- find redirect map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct REDIRECT);
	mapinfo.max_entries = MAX_REDIRECT_NUM;
	int map_fd;
	map_fd = map_lookup(net, rdtmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find redirect map %s\n", rdtmap_name);
		exit(-1);
	} 
	//------------- find redirect map end ----------

	__u32 key = -1;
	int mkey = 0;
	struct REDIRECT redirect;
	int err;
	void *keyp = &key, *prev_keyp = NULL;
	while (true)
	{ 
        err = bpf_map_get_next_key(map_fd, prev_keyp, keyp);
        if (err) {
            if (errno == ENOENT)
                err = 0;
            break;
         }

        if ((bpf_map_lookup_elem(map_fd, keyp, &redirect)) != 0) 
		{
            fprintf(stderr,
                "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
            continue;
        }
		if (!redirect.valid)
		{
			mkey = *(int*)keyp;
			break;
		}
        prev_keyp = keyp;
	} 

  return mkey;
}


int
is_valid_path_key(char *net, __u32 key)
{
	if (key>MAX_PATH_NUM || key<0)
		return 0;
	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct PATH);
	mapinfo.max_entries = MAX_PATH_NUM;
	int map_fd;
	map_fd = map_lookup(net, patmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", flwmap_name);
		exit(-1);
	}
	//------------- find path map end ----------

	//------------- just every entry in path map -----
	struct PATH path;
	//p_path = bpf_map_lookup_elem(xdp_map, &j);
	if ((bpf_map_lookup_elem(map_fd, &key, &path)) != 0) 
	{
		fprintf(stderr, "ERR: bpf_map_lookup_elem failed key:0x%X\n", key);
		return 0;
	}
	printf("key=%d, path valid=%d, ipv4=%d\n", key, path.valid, path.ipv4[0]);
	if (!path.valid)
		return 0;
	else 
		return 1;

}

static void 
update_sid_map(char *net, struct SID *p_sid) 
{
  printf("Updating Sid Map\n");
  __u32 key = find_min_available_key_sid(net);
  if (key>=MAX_SID_NUM || key<0)
  {
	  printf("--- the key=%d out of MAX!\n", key);
	  return;
  }

	//------------- find sid map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct SID);
	mapinfo.max_entries = MAX_SID_NUM;
	int map_fd;
	map_fd = map_lookup(net, sidmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", sidmap_name);
		exit(-1);
	}
	//------------- find sid map end ----------

	p_sid->valid = 1;
  if (bpf_map_update_elem(map_fd, &key, p_sid, 0) < 0) 
  {
    fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
            strerror(errno));
    exit(-1);
  }

  return;
}

static void 
update_path_map(char *net, struct PATH *p_path) 
{
  printf("Updating Path Map\n");
  __u32 key = find_min_available_key_path(net);
  if (key>=MAX_PATH_NUM || key<0)
  {
	  printf("--- the key=%d out of MAX!\n", key);
	  return;
  }

	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct PATH);
	mapinfo.max_entries = MAX_PATH_NUM;
	int map_fd;
	map_fd = map_lookup(net, patmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", patmap_name);
		exit(-1);
	}
	//------------- find path map end ----------

  uint8_t key8 = (uint8_t) key;
  p_path->valid = 1;
  p_path->id = key8;
  if (bpf_map_update_elem(map_fd, &key, p_path, 0) < 0) 
  {
    fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
            strerror(errno));
    exit(-1);
  }

  return;
}

static void 
update_flow_map(char *net, struct FLOW *p_flow) 
{
  printf("Updating Flow Map\n");
  __u32 key = find_min_available_key_flow(net);
  if (key>MAX_FLOW_NUM || key<0)
  {
	  printf("--- the key out of MAX!\n");
	  exit(-1);
  }
  if (!is_valid_path_key(net, p_flow->id))
  {
	  printf("--- the path whose index is %d is invalid\n", p_flow->id);
	  exit(-1);
  }

	//------------- find flow map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct FLOW);
	mapinfo.max_entries = MAX_FLOW_NUM;
	int map_fd;
	map_fd = map_lookup(net, flwmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", flwmap_name);
		exit(-1);
	}
	//------------- find flow map end ----------

  p_flow->valid = 1;
  if (bpf_map_update_elem(map_fd, &key, p_flow, 0) < 0) 
  {
    fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
            strerror(errno));
    exit(-1);
  } 

  return;
}

static void 
update_redirect_map(char *net, struct REDIRECT *p_redirect) 
{
  printf("Updating Redirect Map\n");
  __u32 key = find_min_available_key_redirect(net);
  if (key>=MAX_SID_NUM || key<0)
  {
	  printf("--- the key=%d out of MAX!\n", key);
	  return;
  }

	//------------- find sid map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct REDIRECT);
	mapinfo.max_entries = MAX_REDIRECT_NUM;
	int map_fd;
	map_fd = map_lookup(net, rdtmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", rdtmap_name);
		exit(-1);
	}
	//------------- find sid map end ----------

	p_redirect->valid = 1;
  if (bpf_map_update_elem(map_fd, &key, p_redirect, 0) < 0) 
  { 
    fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
            strerror(errno));
    exit(-1);
  }

  return;
}


static int
ipv4_parse(uint32_t ipv4_u32[MAX_NODE_NUM], const char* param)
{
  char *seg;
  int i;
  for (i=0; i<MAX_NODE_NUM; i++)
	  ipv4_u32[i] = 0;
  i = 0;
  seg = strtok(param, ",");
  while (seg != NULL && i < MAX_NODE_NUM) 
  {
	ipstr2int(&ipv4_u32[i], seg);
    seg = strtok(NULL, ",");
    i++;
  }
	return i;
}

static int
flow_parse(struct FLOW* flow, const char* param)
{
	char *seg;
	int i;
	i = 0;
	seg = strtok(param, ",");
	while (seg != NULL && i < MAX_NODE_NUM) 
	{
		if (i == 0)
			ipstr2int(&(flow->src_ipv4), seg);
		if (i == 1)
			ipstr2int(&(flow->dst_ipv4), seg);
		if (i == 2)
			flow->src_port = atoi(seg); 
		if (i == 3)
			flow->dst_port = atoi(seg); 
		seg = strtok(NULL, ",");
		i++;
	}
	return 0;
}



uint8_t 
s2i_act(char* str)
{
	if(strcmp(str, "PASS")==0) return 0;
	if(strcmp(str, "END")==0) return 1;
	if(strcmp(str, "ENCAP")==0) return 2;
	if(strcmp(str, "DENCAP")==0) return 3;
	return 255;
}
int
i2s_act(char str[10], uint8_t act)
{
	switch (act)
	{
		case 0:
			strcpy(str, "PASS");
			break;
		case 1:
			strcpy(str, "END");
			break;
		case 2:
			strcpy(str, "ENCAP");
			break;
		case 3:
			strcpy(str, "DENCAP");
			break;
		default:
			strcpy(str, "");
			return -1;
	}
	return 0;
}
void
print_sid_map(char *net)
{
	printf("Print SID Map:\n");

	//------------- find sid map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct SID);
	mapinfo.max_entries = MAX_SID_NUM;
	int map_fd;
	map_fd = map_lookup(net, sidmap_name, &mapinfo);
	//printf("map_fd = %d\n", map_fd);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", sidmap_name);
		exit(-1);
	}
	//------------- find sid map end ----------

	//------------- find the count of sid entries -----
	int count;
	count = MAX_SID_NUM;

	//------------- print every entry in sid map -----
	int j;
	struct SID sid;
	uint8_t ip[4];
	char ipstr[16];	
	char act_str[10];
	for (j=0; j<count; j++)
	{
		if ((bpf_map_lookup_elem(map_fd, &j, &sid)) != 0) 
		{
			fprintf(stderr, "ERR: bpf_map_lookup_elem failed key:0x%X\n", j);
			continue;
		}
		if (!sid.valid)
			continue;
		int2ip(ip, sid.ipv4);
		ip2str(ipstr, ip);
		i2s_act(act_str, sid.action);
		printf("--- key %d, ip %s   action %s\n", j, ipstr, act_str);
	}

	return ;
}

void
print_path_map(char *net)
{
	printf("Print PATH Map:\n");

	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct PATH);
	mapinfo.max_entries = MAX_PATH_NUM;
	int map_fd;
	map_fd = map_lookup(net, patmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", patmap_name);
		exit(-1);
	}
	//------------- find path map end ----------

	//------------- find the count of entried in path map -----
	int count;
	count = MAX_PATH_NUM;

	//------------- print every entry in path map -----
	int i, j;
	struct PATH path;
	uint8_t ip[4];
	char ipstr[16];	
	for (j=0; j<count; j++)
	{
		if ((bpf_map_lookup_elem(map_fd, &j, &path)) != 0) 
		{
			fprintf(stderr, "ERR: bpf_map_lookup_elem failed key:0x%X\n", j);
		}
		if (!path.valid)
			continue;
		int2ip(ip, path.ipv4[0]);
		ip2str(ipstr, ip);
		printf("--- key %d, valid %d, ip %s", j, path.valid, ipstr);
		for (i=1; i<path.num; i++)
		{
			int2ip(ip, path.ipv4[i]);
			ip2str(ipstr, ip);
			printf(",%s", ipstr);
		}
		printf("\n");
	}

	return ;
}

void
print_flow_map(char *net)
{
	printf("Print FLOW Map:\n");

	//------------- find flow map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct FLOW);
	mapinfo.max_entries = MAX_FLOW_NUM;
	int map_fd;
	map_fd = map_lookup(net, flwmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", flwmap_name);
		exit(-1);
	}
	//------------- find flow map end ----------

	//------------- find the count of entries in flow map -----
	int count;
	count = MAX_FLOW_NUM;

	//------------- print every entry in flow map -----
	int j;
	struct FLOW flow;
	uint8_t ip[4];
	char ipstr[16];	
	for (j=0; j<count; j++)
	{
		if ((bpf_map_lookup_elem(map_fd, &j, &flow)) != 0) 
		{
			fprintf(stderr, "ERR: bpf_map_lookup_elem failed key:0x%X\n", j);
		}
		if (!flow.valid)
			continue;
		int2ip(ip, flow.src_ipv4);
		ip2str(ipstr, ip);
		printf("--- key %d, flow %s,", j, ipstr);
		int2ip(ip, flow.dst_ipv4);
		ip2str(ipstr, ip);
		printf("%s,%d,%d pathid=%d timeout=%u\n", ipstr, flow.src_port, flow.dst_port, flow.id, flow.timeout);
	}

	return ;
}

void
print_redirect_map(char *net)
{
	printf("Print REDIRECT Map:\n");

	//------------- find redirect map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct REDIRECT);
	mapinfo.max_entries = MAX_REDIRECT_NUM;
	int map_fd;
	map_fd = map_lookup(net, rdtmap_name, &mapinfo);
	if (map_fd < 0)
	{ 
		printf("Do not find map %s\n", rdtmap_name);
		exit(-1);
	}
	//------------- find redirect map end ----------

	//------------- find the count of sid entries -----
	int count;
	count = MAX_REDIRECT_NUM;

	//------------- print every entry in redirect map -----
	int j;
	struct REDIRECT rdi;
	uint8_t ip[4];
	char ifname[20];
	char ipstr[16];	
	for (j=0; j<count; j++)
	{
		if ((bpf_map_lookup_elem(map_fd, &j, &rdi)) != 0) 
		{ 
			fprintf(stderr, "ERR: bpf_map_lookup_elem failed key:0x%X\n", j);
			continue;
		}
		if (!rdi.valid)
			continue;
		int2ip(ip, ntohl(rdi.ipv4));
		ip2str(ipstr, ip);
		if_indextoname(rdi.egr_ifi, ifname);
		printf("--- key %d, ip %s   egress if %d %s, s_eth %02x:%02x:%02x:%02x:%02x:%02x, d_eth %02x:%02x:%02x:%02x:%02x:%02x \n", j, ipstr, rdi.egr_ifi, ifname, rdi.eth_source[0], rdi.eth_source[1], rdi.eth_source[2], rdi.eth_source[3], rdi.eth_source[4], rdi.eth_source[5], rdi.eth_dest[0], rdi.eth_dest[1], rdi.eth_dest[2], rdi.eth_dest[3], rdi.eth_dest[4], rdi.eth_dest[5]);
	}

	return ;
}

void
delete_sid_map(char *net, int delete_i)
{
	printf("Delete Sid Map key=%d\n", delete_i);
	if (delete_i>=MAX_SID_NUM || delete_i<0)
	{
		printf("--- the index of entry to delete out of MAX!\n");
		return;
	}

	//------------- find sid map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct SID);
	mapinfo.max_entries = MAX_SID_NUM;
	int map_fd;
	map_fd = map_lookup(net, sidmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", sidmap_name);
		exit(-1);
	}
	//------------- find sid map end ----------

	struct SID sid;
	sid.valid = 0;
	sid.ipv4 = 0;
	sid.action = 100000;

	__u32 key = (__u32) delete_i;
	if (bpf_map_update_elem(map_fd, &key, &sid, 0) < 0) 
	{
		fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
				strerror(errno));
		exit(-1);
	}

	return ;
}

static void 
delete_flow_map(char *net, int delete_i) 
{
  printf("Deleting Flow Map\n");
  //int key = get_map_count(net, FLOW_MAP);
  if (delete_i>=MAX_FLOW_NUM || delete_i<0)
  { 
	  printf("--- the index of entry to delete out of MAX!\n");
	  return;
  }

	//------------- find flow map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct FLOW);
	mapinfo.max_entries = MAX_FLOW_NUM;
	int map_fd;
	map_fd = map_lookup(net, flwmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", flwmap_name);
		exit(-1);
	}
	//------------- find flow map end ----------
	struct FLOW flow;
	flow.valid = 0;
	flow.id = 0;
	flow.src_port = 0;
	flow.dst_port = 0;
	flow.src_ipv4 = 0;
	flow.dst_ipv4 = 0;

	__u32 key = (__u32) delete_i;
	if (bpf_map_update_elem(map_fd, &key, &flow, 0) < 0) 
	{
		fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
				strerror(errno));
		exit(-1);
	}

  return;
}

static void 
delete_path_map(char *net, int delete_i) 
{
  printf("Deleting Path Map\n");
  if (delete_i>=MAX_PATH_NUM || delete_i<0)
  {
	  printf("--- the index of entry to delete out of MAX!\n");
	  return;
  }

	//------------- find path map beginning ... ----------
	struct bpf_map_info mapinfo = { 0 };
	mapinfo.key_size = sizeof(__u32);
	mapinfo.value_size = sizeof(struct PATH);
	mapinfo.max_entries = MAX_PATH_NUM;
	int map_fd;
	map_fd = map_lookup(net, patmap_name, &mapinfo);
	if (map_fd < 0)
	{
		printf("Do not find map %s\n", patmap_name);
		exit(-1);
	}
	//------------- find path map end ----------
	
	struct PATH path;
	path.valid = 0;
	path.id = 10000;
	path.num = 10000;
	for (int j=0; j<MAX_NODE_NUM; j++)
		path.ipv4[j] = 0;

	__u32 key = (__u32) delete_i;
	if (bpf_map_update_elem(map_fd, &key, &path, 0) < 0) 
	{
		fprintf(stderr, "WARN: Failed to update bpf map file: err(%d):%s\n", errno,
				strerror(errno));
		exit(-1);
	}

  return;
}

int main(int argc, char **argv) 
{
	char net[100];

	int ch;
	bool interface_given = false;
	bool do_update_sid_map_s = false;
	bool do_update_sid_map_a = false;
	bool do_update_path_map = false;
	bool do_update_flow_map_f = false;
	bool do_update_flow_map_n = false;
	bool do_list_sid_map = false;
	bool do_list_path_map = false;
	bool do_list_flow_map = false;
	bool do_list_redirect_map = false;
	bool do_delete_sid_map = false;
	bool do_delete_path_map = false;
	bool do_delete_flow_map = false;
	bool do_delete_i = false;
	int delete_i = -1;
	char ipv4_str[16];
	struct SID sid_usr = {0};
	struct PATH path_usr = {0};
	struct FLOW flow_usr = {0};
	struct REDIRECT redirect_usr = {0};

	usage(argv[0], __doc__, long_options, (argc == 1));
	while ((ch = getopt(argc, argv, "s:a:p:f:n:t:i:l:d:D:r:e:")) != -1) 
	{
		switch (ch) {
			case 'D':
				memcpy(net, optarg, 100);
				interface_given = true;
				break;
			// -s and -a to add a sid
			case 's':
				memcpy(ipv4_str, optarg, 16);
				ipstr2int(&(sid_usr.ipv4), ipv4_str);
				do_update_sid_map_s = true;
				break;
			case 'a':
				sid_usr.action = s2i_act(optarg);
				if (sid_usr.action == 255)
					exit(-1);
				do_update_sid_map_a = true;
				break;
				// -p to add a path
			case 'p':
				// parse ipv4 list 
				path_usr.num = ipv4_parse(path_usr.ipv4, optarg);
				do_update_path_map = true;
				break;
				// -f and -n to add a flow
			case 'f':
				flow_parse(&flow_usr, optarg);
				do_update_flow_map_f = true;
				break;
			case 'n':
				// parse segmentpath
				flow_usr.id = atoi(optarg);
				do_update_flow_map_n = true;
				break;
				// -l to list map
			case 'l':
				// to list SID map
				if (strcmp(optarg, "s") == 0)
					do_list_sid_map = true;
				// to list PATH map
				if (strcmp(optarg, "p") == 0)
					do_list_path_map = true;
				// to list FLOW map
				if (strcmp(optarg, "f") == 0)
					do_list_flow_map = true;
				// to list REDIRECT map
				if (strcmp(optarg, "r") == 0)
					do_list_redirect_map = true;
				break;
				// -d and -i to delete an entry of a map
			case 'd':
				// to delete an entry of SID map
				if (strcmp(optarg, "s") == 0)
					do_delete_sid_map = true;
				// to delete an entry of PATH map
				if (strcmp(optarg, "p") == 0)
					do_delete_path_map = true;
				// to delete an entry of FLOW map
				if (strcmp(optarg, "f") == 0)
					do_delete_flow_map = true;
				break;
				// -i to indicate the index of entry to delete
			case 'i':
				delete_i = atoi(optarg);
				do_delete_i = true;
				break;
			default:
				usage(argv[0], __doc__, long_options, (argc == 1));
				fprintf(stderr, "Invalid argument\n");
				exit(-1);
		}
	}

	if (!interface_given)
	{
		printf("Please give the interface!\n");
		exit(-1);
	}

	// list MAP
	if (do_list_sid_map)
		print_sid_map(net);
	if (do_list_path_map)
		print_path_map(net);
	if (do_list_flow_map)
		print_flow_map(net);
	if (do_list_redirect_map)
		print_redirect_map(net);
	
	// update MAP
	if (do_update_sid_map_s && do_update_sid_map_a)
		update_sid_map(net, &sid_usr);
	if (do_update_path_map)
		update_path_map(net, &path_usr);
	if (do_update_flow_map_f && do_update_flow_map_n)
		update_flow_map(net, &flow_usr);

	// delete an entry from an map
	if (do_delete_sid_map && do_delete_i)
		delete_sid_map(net, delete_i);
	if (do_delete_path_map && do_delete_i)
		delete_path_map(net, delete_i);
	if (do_delete_flow_map && do_delete_i)
		delete_flow_map(net, delete_i);

	return 0;
}




